const RENDER_TO_DOM = Symbol("render to dom");

class ElementWapper {
    constructor(type) {
        this.root = document.createElement(type);
    }
    setAttribute(name, value) {
        // 支持事件监听
        if (name.match(/^on([\s\S]+)$/)) {
            this.root.addEventListener(RegExp.$1.replace(/^[\s\S]/, c => c.toLowerCase()), value);
        } else {
            // 支持设置类语法
            if (name === "className") {
                this.root.setAttribute("class", value)
            } else {
                this.root.setAttribute(name, value);
            }
        }
    }

    appendChild(component) {
        let range = document.createRange();
        range.setStart(this.root, this.root.childNodes.length);
        range.setEnd(this.root, this.root.childNodes.length);
        component[RENDER_TO_DOM](range);
    }

    [RENDER_TO_DOM](range) {
        range.deleteContents();
        range.insertNode(this.root);
    }
}

class TextWapper {
    constructor(content) {
        this.root = document.createTextNode(content);
    }

    [RENDER_TO_DOM](range) {
        range.deleteContents();
        range.insertNode(this.root);
    }
}

export class Component {
    constructor() {
        this.props = Object.create(null);
        this.children = [];
        this._root = null;
        this._range = null;
    }

    setAttribute(name, value) {
        this.props[name] = value;
    }

    appendChild(component) {
        this.children.push(component);
    }

    // 用中括号可以把字符作为一个变量使用， 使用sybal来实现私有方法
    [RENDER_TO_DOM](range) {
        this._range = range;
        this.render()[RENDER_TO_DOM](range);
    }

    // 重新绘制dom
    rerender() {
        let oldRange = this._range;
        // 因为range会有个隐性的bug，就是当range为空的时候有相邻的rage存在时，相邻的不为空的range会合并空range
        let range = document.createRange();
        range.setStart(oldRange.startContainer, oldRange.startOffset);
        range.setEnd(oldRange.startContainer, oldRange.startOffset);
        this[RENDER_TO_DOM](range);

        oldRange.setStart(range.endContainer, range.endOffset);
        oldRange.deleteContents();
    
    }

    setState(newState) {
        if(this.state === null || typeof this.state !== "object" ) {
            this.state = newState;
            this.rerender();
            return;
        }

        let merge = (oldState, newState) => {
            for(let p in newState) {
                if(oldState[p] === null || typeof oldState[p] !== "object") {
                    oldState[p] = newState[p];
                } else {
                    merge(oldState[p], newState[p]);
                }
            }
        };
        merge(this.state, newState);
        this.rerender();
    }
}

export function createElement(type, attributes, ...children) {
    let elem;
    if (typeof type === "string") {
        elem = new ElementWapper(type);
    } else {
        elem = new type;
    }

    // 把赋值进来的标签属性，添加到dom对象elem中
    for (let attr in attributes) {
        elem.setAttribute(attr, attributes[attr]);
    }

    let insertChildren = (children) => {
        // 添加子节点
        for (let child of children) {
            if (typeof child === "string") {
                child = new TextWapper(child);
            }
            // 如果子节点本身为null，那么不处理
            if (child === null) {
                continue;
            }
            if ((typeof child === "object") && (child instanceof Array)) {
                insertChildren(child);
            } else {
                elem.appendChild(child);
            }
        }
    }
    insertChildren(children);
    return elem;
}

export function render(component, parentElement) {
    // https://www.cnblogs.com/lijinwen/p/6254148.html
    let range = document.createRange();
    range.setStart(parentElement, 0);
    range.setEnd(parentElement, parentElement.childNodes.length);
    range.deleteContents();
    component[RENDER_TO_DOM](range);
}